//////////////////////////////////////////////
// PbsMaterial.h
//
//////////////////////////////////////////////

/// Defines / Macros -------------------------

#pragma once

/// Program ----------------------------------

namespace nkAstraeus
{
	class System ;
}

namespace nkGraphics
{
	class Camera ;
	class Program ;
	class Texture ;
}

/// Includes ---------------------------------

// nkAstraeus
#include "../../../Dll/DllDefines.h"

#include "../../Enums/OneChannelPack.h"
#include "../../Enums/ThreeChannelPack.h"

#include "../Material.h"

#include "PbsMaterialInfo.h"

// nkMemory
#include <NilkinsMemory/Pointers/UniquePtr.h>

/// Class ------------------------------------

namespace nkAstraeus
{
	class DLL_ASTRAEUS_EXPORT PbsMaterial final : public Material
	{
		public :

			// Constructor, destructor
			PbsMaterial (System* system) noexcept ;
			virtual ~PbsMaterial () ;

			// Getters
			nkMemory::StringView getPositionAttributeName () const ;
			nkMemory::StringView getTexCoordAttributeName () const ;
			nkMemory::StringView getNormalAttributeName () const ;
			nkMemory::StringView getTangentAttributeName () const ;
			nkMemory::StringView getBinormalAttributeName () const ;
			nkMaths::Vector getLightDirection () const ;
			nkMaths::Vector getLightColor () const ;
			nkMaths::Vector getAlbedoColor () const ;
			nkMaths::Vector getSpecularColor () const ;
			nkMaths::Vector getEmissiveColor () const ;
			nkMaths::Vector getEnvironmentColor () const ;
			float getMetalness () const ;
			float getRoughnessGlossiness () const ;
			float getAlpha () const ;
			float getAlphaCutoff () const ;
			nkGraphics::Texture* getAlbedoTexture () const ;
			nkGraphics::Texture* getSpecularTexture () const ;
			nkGraphics::Texture* getEmissiveTexture () const ;
			nkGraphics::Texture* getMetalnessTexture () const ;
			nkGraphics::Texture* getRoughnessGlossinessTexture () const ;
			nkGraphics::Texture* getAlphaTexture () const ;
			nkGraphics::Texture* getOcclusionTexture () const ;
			nkGraphics::Texture* getNormalMapTexture () const ;
			nkGraphics::Texture* getEnvironmentTexture () const ;
			nkGraphics::Texture* getIrradianceTexture () const ;
			THREE_CHANNEL_PACK getAlbedoTextureChannels () const ;
			THREE_CHANNEL_PACK getSpecularTextureChannels () const ;
			THREE_CHANNEL_PACK getEmissiveTextureChannels () const ;
			ONE_CHANNEL_PACK getMetalnessTextureChannels () const ;
			ONE_CHANNEL_PACK getRoughnessGlossinessTextureChannels () const ;
			ONE_CHANNEL_PACK getAlphaTextureChannels () const ;
			ONE_CHANNEL_PACK getOcclusionTextureChannels () const ;
			THREE_CHANNEL_PACK getNormalMapTextureChannels () const ;
			THREE_CHANNEL_PACK getEnvironmentTextureChannels () const ;
			THREE_CHANNEL_PACK getIrradianceTextureChannels () const ;
			nkGraphics::Texture* getShadowMapTexture () const ;
			nkGraphics::Camera* getShadowMapCamera () const ;
			const ShadowMapParameters& getShadowMapParameters () const ;
			PBS_MODEL getPbsModel () const ;
			bool getEnvironmentTextureIsCubeByDefault () const ;
			bool getIrradianceTextureIsCubeByDefault () const ;
			bool getReconstructBinormals () const ;
			bool getMixAlbedoColorAndTexture () const ;
			bool getMixSpecularColorAndTexture () const ;
			bool getMixEmissiveColorAndTexture () const ;
			bool getMixMetalnessFactorAndTexture () const ;
			bool getMixRoughnessGlossinessFactorAndTexture () const ;
			bool getMixEnvironmentColorAndTexture () const ;
			bool getMixAlphaFactorAndTexture () const ;
			bool getCombineLightAndEnvironment () const ;

			// Setters
			void setPositionAttributeName (nkMemory::StringView value) ;
			void setTexCoordAttributeName (nkMemory::StringView value) ;
			void setNormalAttributeName (nkMemory::StringView value) ;
			void setTangentAttributeName (nkMemory::StringView value) ;
			void setBinormalAttributeName (nkMemory::StringView value) ;
			void setLightDirection (const nkMaths::Vector& value) ;
			void setLightColor (const nkMaths::Vector& value) ;
			void setAlbedoColor (const nkMaths::Vector& value) ;
			void setSpecularColor (const nkMaths::Vector& value) ;
			void setEmissiveColor (const nkMaths::Vector& value) ;
			void setEnvironmentColor (const nkMaths::Vector& value) ;
			void setMetalness (float value) ;
			void setRoughnessGlossiness (float value) ;
			void setAlpha (float value) ;
			void setAlphaCutoff (float value) ;
			void setAlbedoTexture (nkGraphics::Texture* value, THREE_CHANNEL_PACK channels = THREE_CHANNEL_PACK::RGB) ;
			void setSpecularTexture (nkGraphics::Texture* value, THREE_CHANNEL_PACK channels = THREE_CHANNEL_PACK::RGB) ;
			void setEmissiveTexture (nkGraphics::Texture* value, THREE_CHANNEL_PACK channels = THREE_CHANNEL_PACK::RGB) ;
			void setMetalnessTexture (nkGraphics::Texture* value, ONE_CHANNEL_PACK channel = ONE_CHANNEL_PACK::A) ;
			void setRoughnessGlossinessTexture (nkGraphics::Texture* value, ONE_CHANNEL_PACK channel = ONE_CHANNEL_PACK::A) ;
			void setAlphaTexture (nkGraphics::Texture* value, ONE_CHANNEL_PACK channel = ONE_CHANNEL_PACK::A) ;
			void setOcclusionTexture (nkGraphics::Texture* value, ONE_CHANNEL_PACK channel = ONE_CHANNEL_PACK::A) ;
			void setNormalMapTexture (nkGraphics::Texture* value, THREE_CHANNEL_PACK channels = THREE_CHANNEL_PACK::RGB) ;
			void setEnvironmentTexture (nkGraphics::Texture* value, THREE_CHANNEL_PACK channels = THREE_CHANNEL_PACK::RGB, bool prefilteredEnv = false) ;
			void setIrradianceTexture (nkGraphics::Texture* value, THREE_CHANNEL_PACK channels = THREE_CHANNEL_PACK::RGB) ;
			void setShadowMapTexture (nkGraphics::Texture* value, nkGraphics::Camera* shadowCamera, const ShadowMapParameters& parameters = ShadowMapParameters()) ;
			void setPbsModel (PBS_MODEL value) ;
			void setEnvironmentTextureIsCubeByDefault (bool value) ;
			void setIrradianceTextureIsCubeByDefault (bool value) ;
			void setReconstructBinormals (bool value) ;
			void setMixAlbedoColorAndTexture (bool value) ;
			void setMixSpecularColorAndTexture (bool value) ;
			void setMixEmissiveColorAndTexture (bool value) ;
			void setMixMetalnessFactorAndTexture (bool value) ;
			void setMixRoughnessGlossinessFactorAndTexture (bool value) ;
			void setMixEnvironmentColorAndTexture (bool value) ;
			void setMixAlphaFactorAndTexture (bool value) ;
			void setCombineLightAndEnvironment (bool value) ;

			// Load
			virtual bool load () override ;
			virtual void unload () override ;

			// Import / export
			virtual void exportClassToTree (nkExport::Node* rootNode) override ;
			virtual void importClassFromTree (nkExport::Node* rootNode) override ;

		public :

			// Statics
			static nkMemory::UniquePtr<PbsMaterial> create (System* system = nullptr) ;

		private :

			// Functions
			// Loading related
			bool _packTextureSlots () ;
			bool _prepareProgram () ;
			bool _prepareShader () ;

		private :

			// Attributes
			// Program used for PBS
			System* _system ;
			nkGraphics::Program* _program ;
			PbsMaterialInfo _programInfo ;

			// Active program info
			PbsMaterialInfo _info ;
	} ;
}